package com.tiancheng.onecode.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.util.*;

/**
 * 日期、时间工具类
 *
 * @author luffy
 * @date 2019/3/12
 */
public final class DateTimeUtil {

    private static final String utc_pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private static final String gmt_pattern = "yyyy-MM-dd'T'HH:mm:ssX";
    public static final String bj_pattern = "yyyy-MM-dd HH:mm:ss";
    private static final String pst_pattern = "HH:mm:ss MMM dd, yyyy";

    public static final String BEIJING = "Asia/Shanghai";  //也可以使用"+8" 北京在东8区

    public static final String US_PST = "America/Los_Angeles";  //也可以使用"-8" 太平洋标准时区

    /**
     * String to LocalDate
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDate}
     */
    public static LocalDate string2LocalDate(String dateTime, String pattern) {
        return LocalDate.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }


    /**
     * String to LocalDateTime
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime string2LocalDateTime(String dateTime, String pattern) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * Date to LocalDate
     *
     * @param date {@link Date}
     * @return {@link LocalDate}
     */
    public static LocalDate date2LocalDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Date to LocalDateTime
     *
     * @param date {@link Date}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * Temporal format to String
     *
     * @param dateTime {@link Temporal}
     * @param pattern  {@link String}
     * @return {@link String}
     */
    public static String temporalFormat2String(Temporal dateTime, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(dateTime);
    }

    /**
     * Timestamp to LocalDate
     *
     * @param timestamp long时间戳
     * @return {@link LocalDate}
     */
    public static LocalDate timestamp2LocalDate(long timestamp) {
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Timestamp to LocalDateTime
     *
     * @param timestamp long时间戳
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime timestamp2LocalDateTime(long timestamp) {
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDateTime to string
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDate}
     */
    public static String formatter(LocalDateTime dateTime, String pattern) {
        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取当天日期 yyyyMMdd
     *
     * @return
     */
    public static String getCurrentDay() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    /**
     * 获取当前时间 HHmmss
     *
     * @return
     */
    public static String getCurrentTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmmss"));
    }
    /**
     * 获取当前时间 yyyyMMddHHmmss
     *
     * @return
     */
    public static String getCurrentDateTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    /**
     * UTC时间转北京时间
     *
     * @param utcTime 国际时间  时间为： 2021-10-27T06:23:09Z   格式为: yyyy-MM-dd'T'HH:mm:ss'Z'
     * @return
     */
    public static LocalDateTime Utc2Beijing(String utcTime) throws ParseException {
        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(utc_pattern);
        srcdate = sdf.parse(utcTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(srcdate);
        calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);

        //SimpleDateFormat simpleDateFormat = new SimpleDateFormat(bj_pattern);
        Date tardate = calendar.getTime();
        return date2LocalDateTime(tardate);
    }

    /**
     * GMT-08:00 时区转为北京时间
     *
     * @param gmtTime 时间为： 2021-10-27T00:33:23-07:00  格式为：yyyy-MM-dd'T'HH:mm:ssX
     * @return
     * @throws ParseException
     */
    public static LocalDateTime GMT2Beijing(String gmtTime) throws ParseException {
        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(gmt_pattern);
        srcdate = sdf.parse(gmtTime);
        return date2LocalDateTime(srcdate);
    }

    /**
     * @param srcTime 23:23:09 Oct 26, 2021 PDT   太平洋夏季时间+15h=北京时间
     *                23:23:09 Nov 26, 2021 PST   太平洋冬季时间+16h=北京时间
     *                太平洋夏季时间从每年3月的第二个星期日到11月的第一个星期日期间和北京时间差15小时，其余月份和北京时间差16小时
     */
    public static LocalDateTime PDTorPST2Beijing(String srcTime) throws ParseException {
        String newSrcTime = "";
        if (srcTime.endsWith("PDT")) {
            newSrcTime = srcTime.substring(0, srcTime.indexOf("PDT")).trim();
        }
        if (srcTime.endsWith("PST")) {
            newSrcTime = srcTime.substring(0, srcTime.indexOf("PST")).trim();
        }

        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(pst_pattern, Locale.US);
        srcdate = sdf.parse(newSrcTime);
        SimpleDateFormat sdf2 = new SimpleDateFormat(bj_pattern);
        System.out.println(date2LocalDateTime(srcdate));
        System.out.println(sdf2.format(srcdate));

        Date target = convertTimezone(srcdate, US_PST, BEIJING);
        long sub = target.getTime() - srcdate.getTime();
        System.out.println("北京时间与洛杉矶时间相差时间: " + sub / (60 * 60 * 1000) + " 小时");
        return date2LocalDateTime(target);
    }

    public static Date convertTimezone(Date sourceDate, String sourceZoneId, String targetZoneId) {
        TimeZone sourceTimeZone = TimeZone.getTimeZone(sourceZoneId);
        TimeZone targetTimeZone = TimeZone.getTimeZone(targetZoneId);
        return convertTimezone(sourceDate, sourceTimeZone, targetTimeZone);
    }

    /**
     * 将sourceDate转换成指定时区的时间
     *
     * @param sourceDate
     * @param sourceTimezone sourceDate所在的时区
     * @param targetTimezone 转化成目标时间所在的时区
     * @return
     */
    public static Date convertTimezone(Date sourceDate, TimeZone sourceTimezone, TimeZone targetTimezone) {

        Calendar calendar = Calendar.getInstance();// date.getTime() 为时间戳, 为格林尼治到系统现在的时间差,世界各个地方获取的时间戳是一样的,       // 格式化输出时,因为设置了不同的时区,所以输出不一样
        long sourceTime = sourceDate.getTime();

        calendar.setTimeZone(sourceTimezone);
        calendar.setTimeInMillis(sourceTime);// 设置之后,calendar会计算各种filed对应的值,并保存

        int targetDaylightOffset = calendar.get(Calendar.DST_OFFSET); // 夏令时

        //获取源时区的到UTC的时区差
        int sourceZoneOffset = calendar.get(Calendar.ZONE_OFFSET);

        calendar.setTimeZone(targetTimezone);
        calendar.setTimeInMillis(sourceTime);

        int targetZoneOffset = calendar.get(Calendar.ZONE_OFFSET);

        long targetTime = sourceTime + targetZoneOffset - sourceZoneOffset - targetDaylightOffset;
        return new Date(targetTime);

    }

    /**
     * 间隔的所有日期
     * @param startDate
     * @param endDate
     * @return
     */
    public static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
        List<LocalDate> dates = new ArrayList<>();
        long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        for (int i = 0; i <= numOfDaysBetween; i++) {
            LocalDate date = startDate.plusDays(i);
            dates.add(date);
        }
        return dates;
    }


}
